#ifndef __M_FMT_H__
#define __M_FMT_H__

#include "util.hpp"
#include "message.hpp"
#include "level.hpp"
#include <memory>
#include <vector>
#include <tuple>

namespace cl{

// 基础格式化项类，定义了格式化日志消息的接口
class FormatItem{
public:
    using ptr = std::shared_ptr<FormatItem>;
    virtual ~FormatItem(){}
    // 纯虚函数，定义格式化方法，子类需要实现
    virtual void format(std::ostream &os, const LogMsg &msg) const = 0;
};

// 消息格式化
class MsgFormatItem : public FormatItem{
public:
    MsgFormatItem(const std::string &str = ""){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << msg._payload;
    }
};

// 日志等级格式化
class LevelFormatItem : public FormatItem{
public:
    LevelFormatItem(const std::string &str = ""){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << LogLevel::toString(msg._level);
    }
};

// 日志器名称格式化
class NameFormatItem : public FormatItem{
public:
    NameFormatItem(const std::string &str = ""){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << msg._name;
    }
};

// 线程ID格式化
class ThreadFormatItem : public FormatItem{
public:
    ThreadFormatItem(const std::string &str = ""){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << msg._tid;
    }
};

// 时间格式化
class TimeFormatItem : public FormatItem{
public:
    TimeFormatItem(const std::string &format = "%H:%M:%S") :_format(format){
        if(format.empty()) _format = "%H:%M:%S";
    }
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        struct tm lt;
        localtime_r(&msg._ctime, &lt);   // 将时间转化为本地时间结构
        char buf[128] = { 0 };
        strftime(buf, sizeof(buf) - 1, _format.c_str(), &lt);   // 格式化时间
        os << buf;
    }
private:
    std::string _format;
};

// 文件名格式化
class CFileFormatItem : public FormatItem{
public:
    CFileFormatItem(const std::string &str = ""){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << msg._file;
    }
};

// 行号格式化
class CLineFormatItem : public FormatItem{
public:
    CLineFormatItem(const std::string &str = ""){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << msg._line;
    }
};

// 制表符格式化
class TabFormatItem : public FormatItem{
public:
    TabFormatItem(const std::string &str = ""){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << "\t";
    }
};

// 换行符格式化
class NLineFormatItem : public FormatItem{
public:
    NLineFormatItem(const std::string &str = ""){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << "\n";
    }
};

// 其他符号格式化，用于输出非格式化的原始字符串
class OtherFormatItem : public FormatItem{
private:
    std::string _str;
public:
    OtherFormatItem(const std::string &str = ""):_str(str){}
    virtual void format(std::ostream &os, const LogMsg &msg) const override {
        os << _str;
    }
};

/**
 * @brief 日志格式器类，用于解析并生成格式化后的日志消息。
 * 
 * 该类负责解析日志的格式化模式，并根据模式输出日志消息。支持多种格式化项，如时间、线程ID、日志级别、文件名等。
 * 可以根据给定的格式化模式灵活地组合不同的格式化项。
 */
class Formatter{
public:
    using ptr = std::shared_ptr<Formatter>;
    /*
    支持的给石化字符及其含义：
        %d 日期时间
        %T 制表符
        %t 线程ID
        %p 日志级别
        %c 日志器名称
        %f 文件名
        %l 行号
        %m 日志消息
        %n 换行符
    */
    // 默认模式：时间{年-月-日 时:分:秒}缩进 线程ID 缩进 [日志级别] 缩进 [日志名称] 缩进 文件名:行号 缩进 消息换行
    Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n")
        :_pattern(pattern){
        assert(parsePattern());     // 解析模式字符串
    }

    // 获取格式化模式字符串
    const std::string& pattern() const { return _pattern; } // 添加&
    // 将日志消息格式化为字符串
    std::string format(const LogMsg &msg){
        std::stringstream ss;
        for(const auto &it : _items){
            it->format(ss, msg);
        }
        return ss.str();
    }

    // 将格式化后的日志消息输出到指定的输出流
    std::ostream& format(std::ostream &os, const LogMsg &msg){
        for(const auto &it : _items){
            it->format(os, msg);
        }
        return os;
    }

    // 根据格式化字符和子格式创建对应的格式化选项
    FormatItem::ptr createItem(const std::string &fmt_char, const std::string &subfmt){
        if(fmt_char == "d") return FormatItem::ptr(new TimeFormatItem(subfmt));
        if(fmt_char == "T") return FormatItem::ptr(new TabFormatItem());
        if(fmt_char == "t") return FormatItem::ptr(new ThreadFormatItem());
        if(fmt_char == "p") return FormatItem::ptr(new LevelFormatItem());
        if(fmt_char == "c") return FormatItem::ptr(new NameFormatItem());
        if(fmt_char == "f") return FormatItem::ptr(new CFileFormatItem());
        if(fmt_char == "l") return FormatItem::ptr(new CLineFormatItem());
        if(fmt_char == "m") return FormatItem::ptr(new MsgFormatItem());
        if(fmt_char == "n") return FormatItem::ptr(new NLineFormatItem());
        if(fmt_char.empty()) return FormatItem::ptr(new OtherFormatItem(subfmt));
        std::cout << "使用非法格式化字符: %" << fmt_char << std::endl;
        return FormatItem::ptr();
    }
    
    // pattern解析，解析格式化模式字符串，将其拆分为格式化项
    bool parsePattern(){
        //std::string _pattern = "sg{}fsg%d{%H:%M:%S}%Tsdf%t%T[%p]%T[%c]%T%f:%l%T%m%n";
        //std::cout << _pattern << std::endl;
        /*
        每个要素分为三部分：
            格式化字符：%d %T %p……
            对应的输出子格式：{%H:%M:%S}
            对应数据的类型：0-表示原始字符串，也就是非格式化字符，1-表示格式化数据类型
            默认格式："%d{%H:%M:%S}%T%t%T[%p]%T[%c]%T%f:%l%T%m%n"
        */
        std::vector<std::tuple<std::string, std::string, int>> tokens;    // 存储解析后的格式化项信息，每个元素包含上面三部分
        std::string format_key; // 存放 % 后的格式化字符
        std::string format_val; // 存放格式化字符后 {} 中的子格式字符串
        std::string string_row; // 存放原始的非格式字符
        bool sub_format_error = false;
        size_t pos = 0;
        while(pos < _pattern.size()){
            if(_pattern[pos] != '%'){
                string_row += _pattern[pos++];
                continue;
            }
            // 处理连续的 %%
            if(pos + 1 < _pattern.size() && _pattern[pos + 1] == '%'){
                string_row += '%';
                pos += 2;
                continue;
            }
            // 将已有的普通文本加入 tokens
            if(!string_row.empty()){
                tokens.emplace_back(string_row, "", 0);
                string_row.clear();
            }
            // 当前位置是%字符位置
            ++pos;   // 跳过 % ，pos指向格式化字符位置
            if(pos < _pattern.size() && isalpha(_pattern[pos])){
                format_key = _pattern[pos]; // 保存格式化字符
            }
            else{
                std::cout << &_pattern[pos-1] << "位置附近格式错误!" << std::endl;
                return false;
            }

            ++pos;   // pos指向格式化字符的下一个位置，判断是否包含有子格式 %d{%y-%m-%d}
            if(pos < _pattern.size() && _pattern[pos] == '{'){
                sub_format_error = true;
                ++pos;   // 跳过 '{'
                while(pos < _pattern.size()){
                    if(_pattern[pos] == '}'){
                        sub_format_error = false;
                        pos += 1;   // 跳过 '}', 让pos指向 } 的下一个字符处
                        break;
                    }
                    format_val += _pattern[pos++];
                }
            }
            // 将格式化项加入 tokens
            tokens.emplace_back(format_key, format_val, 1);
            format_key.clear();
            format_val.clear();
        }
        // 将剩余的普通文本加入 tokens
        if(sub_format_error){
            std::cout << "子规则{}匹配出错" << std::endl;
            return false;
        }
        if(string_row.empty() == false) tokens.emplace_back(string_row, "", 0);
        if(format_key.empty() == false) tokens.emplace_back(format_key, format_val, 1);
        for(auto &token : tokens){
            if(std::get<2>(token) == 0){
                FormatItem::ptr fi(new OtherFormatItem(std::get<0>(token)));
                _items.push_back(fi);
            }
            else{
                FormatItem::ptr item = createItem(std::get<0>(token), std::get<1>(token));
                if(item.get() == nullptr){
                    std::cout << "没有对应的格式化字符：%" << std::get<0>(token) << std::endl;
                    return false;
                }
                _items.push_back(item);
            }
        }
        return true;
    }

private:
    std::string _pattern;               // 格式化模版字符串
    std::vector<FormatItem::ptr> _items; // 格式化项列表
}; // class Formatter
}
#endif